<script setup lang="ts">
import type { SubmitResult } from 'vue-element-plus-x/types/EditorSender';
import type { FilesType } from 'vue-element-plus-x/types/FilesCard';

import { computed, ref } from 'vue';
import { EditorSender, FilesCard } from 'vue-element-plus-x';

import {
  GlobalOutlined,
  PaperClipOutlined,
  ThunderboltOutlined,
} from '@ant-design/icons-vue';
import {
  Badge,
  Button,
  Card,
  message,
  Switch,
  Tag,
  Typography,
  Upload,
} from 'ant-design-vue';

const props = withDefaults(defineProps<Props>(), {
  placeholder: '💬 输入消息...',
  loading: false,
  disabled: false,
  allowSpeech: true,
  presetPrompts: () => [],
  uploadedFiles: () => [],
  enableWebSearch: false,
  enableDeepThinking: false,
});

const emit = defineEmits<Emits>();

const { Text } = Typography;

// 预设提示词类型定义
interface Prompt {
  id: number;
  title: string;
  content: string;
  category: string;
}

// 上传文件类型定义
interface UploadedFile {
  id: string;
  name: string;
  size: number;
  type: string;
  status?: 'error' | 'success' | 'uploading';
  url?: string;
}

interface Props {
  modelValue: string;
  placeholder?: string;
  loading?: boolean;
  disabled?: boolean;
  allowSpeech?: boolean;
  presetPrompts?: Prompt[];
  uploadedFiles?: UploadedFile[];
  enableWebSearch?: boolean;
  enableDeepThinking?: boolean;
}

interface Emits {
  'update:modelValue': [value: string];
  'update:uploadedFiles': [files: UploadedFile[]];
  'update:enableWebSearch': [enabled: boolean];
  'update:enableDeepThinking': [enabled: boolean];
  send: [];
  fileRemove: [fileId: string];
  fileDownload: [fileId: string];
}

const senderValue = computed({
  get: () => props.modelValue,
  set: (value) => emit('update:modelValue', value),
});

const localUploadedFiles = computed({
  get: () => props.uploadedFiles,
  set: (value) => emit('update:uploadedFiles', value),
});

const localEnableWebSearch = computed({
  get: () => props.enableWebSearch,
  set: (value) => emit('update:enableWebSearch', value),
});

const localEnableDeepThinking = computed({
  get: () => props.enableDeepThinking,
  set: (value) => emit('update:enableDeepThinking', value),
});

// 提示词面板显示状态
const showPrompts = ref(false);

// 文件类型颜色映射
const fileColorMap: Record<FilesType, string> = {
  word: '#0078D4',
  excel: '#4CB050',
  ppt: '#FF9933',
  pdf: '#E81123',
  txt: '#666666',
  mark: '#FFA500',
  image: '#B490F3',
  audio: '#00B2EE',
  video: '#2EC4B6',
  three: '#00C8FF',
  code: '#00589F',
  database: '#F5A623',
  link: '#007BFF',
  zip: '#888888',
  file: '#F0D9B5',
  unknown: '#D8D8D8',
};

// 根据文件扩展名获取文件类型
const getFileType = (fileName: string): FilesType => {
  const ext = fileName.split('.').pop()?.toLowerCase() || '';

  // Word 文档
  if (['doc', 'docx'].includes(ext)) return 'word';
  // Excel 表格
  if (['csv', 'xls', 'xlsx'].includes(ext)) return 'excel';
  // PowerPoint 演示文稿
  if (['ppt', 'pptx'].includes(ext)) return 'ppt';
  // PDF 文档
  if (ext === 'pdf') return 'pdf';
  // 文本文件
  if (['text', 'txt'].includes(ext)) return 'txt';
  // Markdown 文件
  if (['markdown', 'md'].includes(ext)) return 'mark';
  // 图片文件
  if (['bmp', 'gif', 'ico', 'jpeg', 'jpg', 'png', 'svg', 'webp'].includes(ext))
    return 'image';
  // 音频文件
  if (['aac', 'flac', 'm4a', 'mp3', 'ogg', 'wav'].includes(ext)) return 'audio';
  // 视频文件
  if (['avi', 'flv', 'mkv', 'mov', 'mp4', 'webm', 'wmv'].includes(ext))
    return 'video';
  // 3D 文件
  if (['3ds', 'fbx', 'glb', 'gltf', 'obj', 'stl'].includes(ext)) return 'three';
  // 代码文件
  if (
    [
      'c',
      'cpp',
      'cs',
      'css',
      'go',
      'html',
      'java',
      'js',
      'json',
      'jsx',
      'kt',
      'less',
      'php',
      'py',
      'rb',
      'rs',
      'scss',
      'swift',
      'ts',
      'tsx',
      'vue',
      'xml',
      'yaml',
      'yml',
    ].includes(ext)
  )
    return 'code';
  // 数据库文件
  if (['db', 'mdb', 'sql', 'sqlite'].includes(ext)) return 'database';
  // 压缩文件
  if (['7z', 'bz2', 'gz', 'rar', 'tar', 'zip'].includes(ext)) return 'zip';
  // 链接文件
  if (['url', 'webloc'].includes(ext)) return 'link';

  return 'file';
};

// 转换为 FilesCard 格式
const filesCardData = computed(() => {
  return localUploadedFiles.value.map((file) => {
    const fileType = getFileType(file.name);
    return {
      uid: file.id,
      name: file.name,
      size: file.size,
      fileType,
      iconColor: fileColorMap[fileType],
      status: file.status,
      url: file.url,
    };
  });
});

const handleSend = (payload: SubmitResult) => {
  if (!payload.text.trim() || props.loading || props.disabled) return;
  emit('send', payload);
};

// 应用预设提示词
const applyPrompt = (prompt: Prompt) => {
  senderValue.value = prompt.content;
  showPrompts.value = false;
};

// 处理文件上传
const handleFileUpload = (file: File) => {
  const uploadedFile: UploadedFile = {
    id: `${Date.now()}-${file.name}`,
    name: file.name,
    size: file.size,
    type: file.type,
    status: 'success',
  };

  const reader = new FileReader();
  reader.addEventListener('load', (e) => {
    uploadedFile.url = e.target?.result as string;
    localUploadedFiles.value = [...localUploadedFiles.value, uploadedFile];
    message.success(`文件 ${file.name} 上传成功`);
  });
  reader.readAsDataURL(file);

  return false; // 阻止自动上传
};

// 处理文件删除
const handleFileRemove = (fileId: string) => {
  const file = localUploadedFiles.value.find(
    (f: UploadedFile) => f.id === fileId,
  );
  localUploadedFiles.value = localUploadedFiles.value.filter(
    (f: UploadedFile) => f.id !== fileId,
  );
  if (file) {
    message.info(`已移除文件 ${file.name}`);
    emit('fileRemove', fileId);
  }
};

// 处理文件下载
const handleFileDownload = (fileId: string) => {
  const file = localUploadedFiles.value.find(
    (f: UploadedFile) => f.id === fileId,
  );
  if (file?.url) {
    const link = document.createElement('a');
    link.href = file.url;
    link.download = file.name;
    link.click();
    message.success(`开始下载 ${file.name}`);
  }
};
</script>

<template>
  <div class="chat-sender-wrapper">
    <!-- 预设提示词标签 -->
    <div
      v-if="props.presetPrompts.length > 0"
      class="mb-3 flex flex-wrap gap-2"
    >
      <Tag
        v-for="prompt in props.presetPrompts.slice(0, 4)"
        :key="prompt.id"
        color="blue"
        @click="applyPrompt(prompt)"
        class="cursor-pointer transition-opacity hover:opacity-80 dark:border-blue-700 dark:bg-blue-900/30"
      >
        {{ prompt.title }}
      </Tag>
      <Button
        type="text"
        size="small"
        @click="showPrompts = !showPrompts"
        class="text-gray-500 dark:text-gray-400"
      >
        {{ showPrompts ? '关闭' : '更多' }}提示词
      </Button>
    </div>

    <!-- 预设提示词面板 -->
    <Card
      v-if="showPrompts && props.presetPrompts.length > 0"
      size="small"
      class="mb-3 border-gray-200 bg-gray-50 dark:border-gray-600 dark:bg-gray-700/50"
    >
      <div class="max-h-60 overflow-y-auto">
        <div
          v-for="prompt in props.presetPrompts"
          :key="prompt.id"
          class="mb-2 cursor-pointer rounded-lg p-2 transition-colors hover:bg-gray-100 dark:hover:bg-gray-600/50"
          @click="applyPrompt(prompt)"
        >
          <div class="text-sm font-medium dark:text-gray-200">
            {{ prompt.title }}
          </div>
          <Text type="secondary" class="mt-1 block text-xs dark:text-gray-400">
            {{ prompt.category }}
          </Text>
        </div>
      </div>
    </Card>
    <!-- 已上传文件列表 -->
    <div v-if="filesCardData.length > 0" class="files-card-container mb-3">
      <FilesCard
        v-for="file in filesCardData"
        :key="file.uid"
        :uid="file.uid"
        :name="file.name"
        :size="file.size"
        :file-type="file.fileType"
        :icon-color="file.iconColor"
        :show-del-icon="true"
        @remove="handleFileRemove(file.uid)"
        @download="handleFileDownload(file.uid)"
      />
    </div>

    <EditorSender
      v-model="senderValue"
      :placeholder="props.placeholder"
      :disabled="props.disabled || props.loading"
      clearable
      :allow-speech="props.allowSpeech"
      variant="updown"
      @submit="handleSend"
    >
      <template #prefix>
        <!-- 功能开关区域 -->
        <div class="flex flex-wrap items-end gap-4" style="min-height: 30px">
          <div class="flex items-center gap-2">
            <Upload
              :before-upload="handleFileUpload"
              :show-upload-list="false"
              accept="image/*,.pdf,.doc,.docx,.txt"
              :multiple="true"
            >
              <Button type="text" size="small" class="flex items-center">
                <PaperClipOutlined class="text-green-500 dark:text-green-400" />
                <span class="text-sm text-gray-700 dark:text-gray-300">
                  文件上传
                </span>
              </Button>
            </Upload>
            <Badge
              v-if="localUploadedFiles.length > 0"
              :count="localUploadedFiles.length"
              :number-style="{ backgroundColor: '#52c41a' }"
              class="ml-1"
            />
          </div>
          <div class="flex items-center gap-2">
            <GlobalOutlined class="text-blue-500 dark:text-blue-400" />
            <span class="text-sm text-gray-700 dark:text-gray-300">
              联网搜索
            </span>
            <Switch v-model:checked="localEnableWebSearch" size="small" />
          </div>
          <div class="flex items-center gap-2">
            <ThunderboltOutlined class="text-purple-500 dark:text-purple-400" />
            <span class="text-sm text-gray-700 dark:text-gray-300">
              深度思考
            </span>
            <Switch v-model:checked="localEnableDeepThinking" size="small" />
          </div>
        </div>
      </template>
    </EditorSender>
  </div>
</template>

<style scoped lang="less">
.chat-sender-wrapper {
  width: 100%;

  .files-card-container {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
  }

  .sender-actions {
    display: flex;
    align-items: center;
    gap: 8px;

    .send-btn {
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      border: none;
      border-radius: 8px;
      padding: 6px 20px;
      height: 36px;
      font-weight: 500;
      transition: all 0.3s ease;

      .dark & {
        background: linear-gradient(135deg, #818cf8 0%, #a78bfa 100%);
      }

      &:hover:not(:disabled) {
        transform: translateY(-2px);
        box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);

        .dark & {
          box-shadow: 0 4px 12px rgba(129, 140, 248, 0.4);
        }
      }

      &:disabled {
        background: #d1d5db;
        cursor: not-allowed;

        .dark & {
          background: #4b5563;
        }
      }
    }
  }
}
</style>
